//----------------------------------Include-------------------------------------
#include <stdint.h>
#include "mcu.h"
#include "board.h"
#include "glbvar.h"
//#include "disp.h"
//------------------------------------------------------------------------------

//-----------------------------------Macro--------------------------------------
#define  _KEY_TOT                   4

#define  _KEY_RS_IDLE               0
#define  _KEY_RS_JITTER_1           1
#define  _KEY_RS_STROKE_1           2
#define  _KEY_RS_JITTER_2           3
#define  _KEY_RS_WAIT_GAP           4
#define  _KEY_RS_JITTER_3           5
#define  _KEY_RS_STROKE_2           6
#define  _KEY_RS_JITTER_4           7
#define  _KEY_RS_LONG_PRESS         8
#define  _KEY_RS_HOLD_PRESS         9
#define  _KEY_RS_DELAY             10

#define  _CNT_IDLE                  100
#define  _CNT_JITTER                 10   //ms
#define  _CNT_STROKE                200
#define  _CNT_WAIT_GAP              400
#define  _CNT_LONG_PRESS_MIN        600
#define  _CNT_LONG_PRESS_MAX       3000
#define  _CNT_DELAY                 800
//------------------------------------------------------------------------------

//-----------------------------------Types--------------------------------------
typedef struct{
  uint32_t   run;
  uint32_t   idle_cnt;
  uint32_t   jitter_cnt;
  uint32_t   stroke_cnt;
  uint32_t   wait_gap_cnt;
  uint32_t   long_press_cnt;
  uint32_t   (*io)(void);
  uint32_t   result;
}t_key;
//------------------------------------------------------------------------------

//---------------------------------Static Var-----------------------------------
static t_key       nt_key[_KEY_TOT];
//------------------------------------------------------------------------------
static uint32_t    nu32_key = 0;
//------------------------------------------------------------------------------

//--------------------------------Static Func-----------------------------------
#if 0
static void _key_proc_simple(t_key* tk)
{
  uint32_t   samp;
  
  if(tk->io == 0) return;
  samp = tk->io();
  
  switch(tk->run){
  case _KEY_RS_IDLE:
    tk->idle_cnt++;
    if(tk->idle_cnt > _CNT_IDLE){
      if(samp) {tk->jitter_cnt = 0; tk->run = _KEY_RS_JITTER_1;}
    }
    break;
  case _KEY_RS_JITTER_1:
    tk->jitter_cnt++;
    if(tk->jitter_cnt > _CNT_JITTER){
      if(samp) {tk->idle_cnt = 0; tk->run = _KEY_RS_IDLE; tk->result = 1;}
      else     {tk->idle_cnt = 0; tk->run = _KEY_RS_IDLE;}
    }
    break;
  case _KEY_RS_DELAY:
    tk->idle_cnt++;
    if(tk->idle_cnt > _CNT_DELAY){
      tk->idle_cnt = 0; tk->run = _KEY_RS_IDLE;
    }
    break;
  default:
    tk->idle_cnt = 0; tk->run = _KEY_RS_DELAY;
    break;
  }
}
#endif

static void _key_proc(t_key* tk)
{
  uint32_t   samp;
  
  if(tk->io == 0) return;
  samp = tk->io();
  
  switch(tk->run){
  case _KEY_RS_IDLE:
    tk->idle_cnt++;
    if(tk->idle_cnt > _CNT_IDLE){
      if(samp) {tk->jitter_cnt = 0; tk->run = _KEY_RS_JITTER_1;}
    }
    break;
  case _KEY_RS_JITTER_1:
    tk->jitter_cnt++;
    if(tk->jitter_cnt > _CNT_JITTER){
      if(samp) {tk->stroke_cnt = 0; tk->run = _KEY_RS_STROKE_1;
      }else    {tk->idle_cnt = 0;   tk->run = _KEY_RS_IDLE;}
    }
    break;
  case _KEY_RS_STROKE_1:
    tk->stroke_cnt++;
    if(tk->stroke_cnt > _CNT_STROKE){
      if(samp) {tk->long_press_cnt = 0; tk->run = _KEY_RS_LONG_PRESS;}
    }
    if(!samp) {tk->jitter_cnt = 0;  tk->run = _KEY_RS_JITTER_2;}
    break;
  case _KEY_RS_JITTER_2:
    tk->jitter_cnt++;
    if(tk->jitter_cnt > _CNT_JITTER){
      if(samp) {tk->idle_cnt = 0;     tk->run = _KEY_RS_IDLE;}
      else     {tk->wait_gap_cnt = 0; tk->run = _KEY_RS_WAIT_GAP;}
    }
    break;
  case _KEY_RS_WAIT_GAP:
    tk->wait_gap_cnt++;
    if(tk->wait_gap_cnt < _CNT_WAIT_GAP){
      if(samp) {tk->jitter_cnt = 0; tk->run = _KEY_RS_JITTER_3;}
    }else{
      if(!samp){tk->result = 1;}  //short stroke
      tk->idle_cnt = 0; tk->run = _KEY_RS_IDLE;
    }
    break;
  case _KEY_RS_JITTER_3:
    tk->jitter_cnt++;
    if(tk->jitter_cnt > _CNT_JITTER){
      if(samp) {tk->stroke_cnt = 0; tk->run = _KEY_RS_STROKE_2;}
      else     {tk->idle_cnt = 0;   tk->run = _KEY_RS_IDLE;}
    }
    break;
  case _KEY_RS_STROKE_2:
    tk->stroke_cnt++;
    if(tk->stroke_cnt > _CNT_STROKE){
      if(samp) {tk->long_press_cnt = 0; tk->run = _KEY_RS_LONG_PRESS;}
    }
    if(!samp) {tk->jitter_cnt = 0; tk->run = _KEY_RS_JITTER_4;}
    break;
  case _KEY_RS_JITTER_4:
    tk->jitter_cnt++;
    if(tk->jitter_cnt > _CNT_JITTER){
      if(!samp) {tk->result = 2;}    //double storke
      tk->idle_cnt = 0; tk->run = _KEY_RS_IDLE;
    }
    break;
  case _KEY_RS_LONG_PRESS:
    tk->long_press_cnt++;
    if(tk->long_press_cnt < _CNT_LONG_PRESS_MIN){
      if(!samp){
        tk->result = 1;      //short press
        tk->idle_cnt = 0; tk->run = _KEY_RS_IDLE;
      }
    }else if(tk->long_press_cnt < _CNT_LONG_PRESS_MAX){
      if(!samp){
        tk->result = 3;      //long press
        tk->idle_cnt = 0; tk->run = _KEY_RS_IDLE;
      }
    }else{
      tk->run = _KEY_RS_HOLD_PRESS;
    }
    break;
  case _KEY_RS_HOLD_PRESS:
    tk->result = 4;    //hold press
    //if(!samp) {tk->idle_cnt = 0; tk->run = _KEY_RS_IDLE; }
    tk->idle_cnt = 0; tk->run = _KEY_RS_IDLE;
    break;
    
  case _KEY_RS_DELAY:
    tk->idle_cnt++;
    if(tk->idle_cnt > _CNT_DELAY){
      tk->idle_cnt = 0; tk->run = _KEY_RS_IDLE;
    }
    break;
  default:
    tk->idle_cnt = 0; tk->run = _KEY_RS_DELAY;
    break;
  }
}
//------------------------------------------------------------------------------

//--------------------------------Public Func-----------------------------------
void key_init(void)
{
  nt_key[0].io = mcu_key_1;
  nt_key[1].io = mcu_key_2;
  nt_key[2].io = mcu_key_3;
  nt_key[3].io = mcu_key_4;
}

uint32_t key_get_brd(void)
{
  uint32_t  key;
  key = nu32_key;
  nu32_key = 0;
  return key;
}

//1   short stroke
//2   double storke
//3   long press
//4   hold press
void icyc_key_proc(void)
{
  uint32_t     i;
  
  for(i=0; i<_KEY_TOT; i++) _key_proc(&nt_key[i]);
  
  if(nt_key[0].result){
    switch(nt_key[0].result){
    case 1:
      mcu_nop();
      break;
    case 2:
      mcu_nop();
      break;
    case 3:
      mcu_nop();
      break;
    case 4:
      mcu_nop();
      break;
    default:break;
    }
    nt_key[0].result = 0;
  }
  if(nt_key[1].result){
    switch(nt_key[1].result){
    case 1:
      mcu_nop();
      break;
    case 2:
      mcu_nop();
      break;
    case 3: 
      mcu_nop();
      break;
    case 4:
      break;
    default:break;
    }
    nt_key[1].result = 0;
  }
  if(nt_key[2].result){
    switch(nt_key[2].result){
    case 1:
      mcu_nop();
      break;
    case 2:
      mcu_nop();
      break;
    case 3: 
      mcu_nop();
      break;
    case 4:
      mcu_nop();
      break;
    default:break;
    }
    nt_key[2].result = 0;
  }
  if(nt_key[3].result){
    switch(nt_key[3].result){
    case 1:
      mcu_nop();
      break;
    case 2:
      mcu_nop();
      break;
    case 3: 
      mcu_nop();
      break;
    case 4:
      mcu_nop();
      break;
    default:break;
    }
    nt_key[3].result = 0;
  }
}
//------------------------------------EOF---------------------------------------

